﻿using Datacollection.Services.Logging;
using System;
using System.IO;
using System.IO.Ports;
using System.Text;
using System.Threading;

namespace SerialDataCollector.Services.Communication
{
    /// <summary>
    /// 串口通信服务类，负责与外部机器进行串口数据交互
    /// </summary>
    public class SerialCommunicator : IDisposable
    {
        /// <summary>
        /// 串口控件实例
        /// </summary>
        private SerialPort _serialPort;

        /// <summary>
        /// 数据接收缓冲区
        /// </summary>
        private readonly StringBuilder _receiveBuffer = new StringBuilder();

        /// <summary>
        /// 接收数据的超时时间（毫秒）
        /// </summary>
        private const int ReceiveTimeout = 5000;

        /// <summary>
        /// 串口是否已打开
        /// </summary>
        public bool IsOpen => _serialPort?.IsOpen ?? false;

        /// <summary>
        /// 数据接收事件（当接收到完整数据帧时触发）
        /// </summary>
        public event Action<string> DataReceived;

        /// <summary>
        /// 串口状态变化事件（打开/关闭/错误）
        /// </summary>
        public event Action<string> StatusChanged;

        /// <summary>
        /// 初始化串口通信类
        /// </summary>
        /// <param name="portName">端口名（如COM1）</param>
        /// <param name="baudRate">波特率</param>
        /// <param name="parity">奇偶校验</param>
        /// <param name="dataBits">数据位</param>
        /// <param name="stopBits">停止位</param>
        public SerialCommunicator(string portName, int baudRate, Parity parity, int dataBits, StopBits stopBits)
        {
            _serialPort = new SerialPort
            {
                PortName = portName,
                BaudRate = baudRate,
                Parity = parity,
                DataBits = dataBits,
                StopBits = stopBits,
                Handshake = Handshake.None, // 无握手协议，可根据设备需求修改
                ReadTimeout = ReceiveTimeout,
                WriteTimeout = 2000,
                Encoding = Encoding.ASCII // 编码方式，根据设备需求调整
            };

            // 注册数据接收事件
            _serialPort.DataReceived += SerialPort_DataReceived;
        }

        /// <summary>
        /// 打开串口
        /// </summary>
        /// <returns>是否打开成功</returns>
        public bool Open()
        {
            try
            {
                if (IsOpen)
                {
                    StatusChanged?.Invoke($"串口 {_serialPort.PortName} 已处于打开状态");
                    return true;
                }

                _serialPort.Open();
                StatusChanged?.Invoke($"串口 {_serialPort.PortName} 已成功打开");
                LogServiceLocator.Logger.Info($"串口 {_serialPort.PortName} 打开成功，波特率：{_serialPort.BaudRate}");
                return true;
            }
            catch (UnauthorizedAccessException)
            {
                string error = $"串口 {_serialPort.PortName} 访问被拒绝（可能被占用或无权限）";
                StatusChanged?.Invoke(error);
                LogServiceLocator.Logger.Error(error);
            }
            catch (IOException)
            {
                string error = $"串口 {_serialPort.PortName} 输入输出错误";
                StatusChanged?.Invoke(error);
                LogServiceLocator.Logger.Error(error);
            }
            catch (ArgumentException)
            {
                string error = $"串口 {_serialPort.PortName} 参数无效";
                StatusChanged?.Invoke(error);
                LogServiceLocator.Logger.Error(error);
            }
            catch (Exception ex)
            {
                string error = $"打开串口 {_serialPort.PortName} 失败：{ex.Message}";
                StatusChanged?.Invoke(error);
                LogServiceLocator.Logger.Error(error, ex);
            }

            return false;
        }

        /// <summary>
        /// 关闭串口
        /// </summary>
        public void Close()
        {
            try
            {
                if (IsOpen)
                {
                    _serialPort.Close();
                    StatusChanged?.Invoke($"串口 {_serialPort.PortName} 已关闭");
                    LogServiceLocator.Logger.Info($"串口 {_serialPort.PortName} 关闭成功");
                }
            }
            catch (Exception ex)
            {
                string error = $"关闭串口 {_serialPort.PortName} 失败：{ex.Message}";
                StatusChanged?.Invoke(error);
                LogServiceLocator.Logger.Error(error, ex);
            }
        }

        /// <summary>
        /// 发送数据（字符串形式）
        /// </summary>
        /// <param name="data">要发送的字符串</param>
        /// <returns>是否发送成功</returns>
        public bool SendData(string data)
        {
            if (!IsOpen)
            {
                StatusChanged?.Invoke("发送失败：串口未打开");
                return false;
            }

            try
            {
                _serialPort.WriteLine(data); // 发送带换行符的字符串（根据设备协议调整）
                LogServiceLocator.Logger.Debug($"通过 {_serialPort.PortName} 发送数据：{data}");
                return true;
            }
            catch (TimeoutException)
            {
                string error = $"发送数据超时（串口 {_serialPort.PortName}）";
                StatusChanged?.Invoke(error);
                LogServiceLocator.Logger.Error(error);
            }
            catch (IOException ex)
            {
                string error = $"发送数据失败（串口 {_serialPort.PortName}）：{ex.Message}";
                StatusChanged?.Invoke(error);
                LogServiceLocator.Logger.Error(error, ex);
            }

            return false;
        }

        /// <summary>
        /// 发送数据（字节数组形式）
        /// </summary>
        /// <param name="data">要发送的字节数组</param>
        /// <returns>是否发送成功</returns>
        public bool SendData(byte[] data)
        {
            if (!IsOpen)
            {
                StatusChanged?.Invoke("发送失败：串口未打开");
                return false;
            }

            try
            {
                _serialPort.Write(data, 0, data.Length); // 发送原始字节
                LogServiceLocator.Logger.Debug($"通过 {_serialPort.PortName} 发送字节：{BitConverter.ToString(data)}");
                return true;
            }
            catch (TimeoutException)
            {
                string error = $"发送数据超时（串口 {_serialPort.PortName}）";
                StatusChanged?.Invoke(error);
                LogServiceLocator.Logger.Error(error);
            }
            catch (IOException ex)
            {
                string error = $"发送数据失败（串口 {_serialPort.PortName}）：{ex.Message}";
                StatusChanged?.Invoke(error);
                LogServiceLocator.Logger.Error(error, ex);
            }

            return false;
        }

        /// <summary>
        /// 串口数据接收事件处理
        /// </summary>
        private void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            try
            {
                // 读取缓冲区所有可用数据
                string received = _serialPort.ReadExisting();
                _receiveBuffer.Append(received);
                LogServiceLocator.Logger.Debug($"从 {_serialPort.PortName} 接收原始数据：{received}");

                // 这里假设数据帧以换行符结束，可根据设备协议修改判断条件
                if (received.Contains(Environment.NewLine) || received.Contains("\n"))
                {
                    string completeData = _receiveBuffer.ToString().Trim();
                    _receiveBuffer.Clear(); // 清空缓冲区

                    // 触发数据接收事件（通知外部处理）
                    DataReceived?.Invoke(completeData);
                    LogServiceLocator.Logger.Info($"从 {_serialPort.PortName} 接收完整数据：{completeData}");
                }
            }
            catch (TimeoutException)
            {
                string error = $"接收数据超时（串口 {_serialPort.PortName}）";
                StatusChanged?.Invoke(error);
                LogServiceLocator.Logger.Error(error);
            }
            catch (Exception ex)
            {
                string error = $"接收数据失败（串口 {_serialPort.PortName}）：{ex.Message}";
                StatusChanged?.Invoke(error);
                LogServiceLocator.Logger.Error(error, ex);
            }
        }

        /// <summary>
        /// 释放资源
        /// </summary>
        public void Dispose()
        {
            Close();
            if (_serialPort != null)
            {
                _serialPort.DataReceived -= SerialPort_DataReceived;
                _serialPort.Dispose();
                _serialPort = null;
            }
        }
    }
}
